const config = require('./config.js');
const axios = require('axios');
const crypto = require('crypto');
const logger = require('./Logger.js'); // 引入日志记录模块
const UserData = require('./UserData.js');

let accessToken = "";
let tokenExpiresIn = 0;//有效期时间，单位秒
let tokenExpiresAt = 0;//过期时间戳
/**
 * 请求抖音的token
 * @returns 
 */
async function requestAccessToken(force = false) {
    // 先判断是否有token
    let needReqToken = false;
    if (accessToken.length > 0) {
        let nowtime = Date.now();
        if (nowtime >= tokenExpiresAt) {
            //过期了
            needReqToken = true;
        }
    }
    else {
        needReqToken = true;
    }
    if (force) {
        needReqToken = true;
    }
    if (needReqToken) {
        const tokenUrl = 'https://minigame.zijieapi.com/mgplatform/api/apps/v2/token';
        const tokenRequestData = {
            appid: config.ttAppId,
            secret: config.ttSecret,
            grant_type: 'client_credential'
        };
        try {
            // 使用axios发送POST请求
            const tokenResponse = await axios.post(tokenUrl, tokenRequestData);
            let data1 = tokenResponse.data;
            let tokenData = data1.data;
            let errNo = data1.err_no;
            let logstr = `请求token，返回数据是${JSON.stringify(tokenData)}, err_no=${errNo}`;
            logger.logMessage(logstr);
            // 检查响应数据是否包含token
            if (tokenData) {
                if (!tokenData.access_token) {
                    logger.logMessage(`token为空`);
                    return;
                }
                accessToken = tokenData.access_token;
                let ead = tokenData.expires_at * 1000;//服务器返回的过期时间戳
                let red = Date.now() + 3600000;//请求取到token后，设置的1个小时后过期的时间戳；
                let tea = Math.min(ead, red);//实际过期时间取最小值
                tokenExpiresAt = tea;
                tokenExpiresIn = tokenData.expires_in;
            }
        } catch (error) {
            logger.logMessage(`请求token接口失败：${error}`);
        }
    }
}

function getToken() {
    return accessToken;
}

/**
 * 更新玩家的离线奖励开始的冷却时间
 * 在每次写入xxx-player-xxx-game文件的时候，解析文件内容，提取hold_reward字段
 * "hold_reward":{"hold_can_video":true,"hold_reward_cooling":1743385688878}
 */
function onUpdateHoldRewardCoolingTime(filename, bodyData, tt_sessionStore) {
    const pattern = /^tt-[a-zA-Z0-9_-]+-player-[a-zA-Z0-9_-]+-game$/;
    let flag = pattern.test(filename);
    if (flag) {
        let pattern2 = /tt-([a-zA-Z0-9_-]+)-player-[a-zA-Z0-9_-]+-game/;
        const match = filename.match(pattern2);
        if (match && match[1]) {
            let openId = match[1];
            try {
                const body = JSON.parse(bodyData);
                if (body && body.hold_reward && body.hold_reward.hold_reward_cooling) {
                    let userData = tt_sessionStore[openId];
                    if (!userData) {
                        userData = new UserData(openId);
                    }
                    userData.setHoldRewardCooling(body.hold_reward.hold_reward_cooling)
                    tt_sessionStore[openId] = userData;
                    console.log(`[${openId}]更新玩家的离线奖励开始的冷却时间, time=${body.hold_reward.hold_reward_cooling}`);
                }
                // else {
                //     logger.logMessage(`[${openId}]解析离线奖励开始的冷却时间，取值为null`);
                // }
            }
            catch (error) {
                logger.logMessage(`[${openId}]解析文件内容失败：${error}`);
            }
        }
        else {
            logger.logMessage("从文件名解析openid出错");
        }
    }
    return [flag, tt_sessionStore];
}

/**
 * 检测是否可以领取离线奖励
 * @param {*} holdRewardCooling 
 * @returns 
 */
function onCheckHoldReward(holdRewardCooling) {
    let canGetAward = false;
    if (holdRewardCooling == 0) {
        canGetAward = true;
    }
    else {
        let t = 1000 * Number(config.ttGuaJiGap);
        let endtime = holdRewardCooling + t;
        canGetAward = Date.now() > endtime;
    }
    return canGetAward;
}
/**
 * 签名计算
 * @param {*} params 
 * @param {*} bodyStr 
 * @returns 
 */
function getSignature(params, bodyStr) {
    // 1. 对url的query参数按key字典序进行排序，排序后，将key-value按顺序连接起来。如：key1=value1&key2=value2。
    const keys = Object.keys(params).sort();
    const kvList = keys.map(key => `${key}=${params[key]}`);
    const urlParams = kvList.join('&');

    // 2. 再直接拼接(无需连接符)上返回体的body字符串和平台分配给开发者的密钥secret。
    const secret = 'lgl522248962qFO';
    const rawData = urlParams + bodyStr + secret;

    // 3. 把拼接好的字符串进行md5计算(16bytes)，并对md5计算结果进行base64编码，编码结果便是x-signature
    const md5sum = crypto.createHash('md5');
    md5sum.update(rawData); // 确保使用UTF-8编码
    const md5Result = md5sum.digest();
    const xSignature = Buffer.from(md5Result).toString('base64');

    // console.log(`生成的signature: ${xSignature}`);
    return xSignature;
}

function getZuiyouSignature(appkey, appsecret, ts, uid) {
    const str = `appkey=${appkey}&appsecret=${appsecret}&ts=${ts}&uid=${uid}`;
    const md5sum = crypto.createHash('md5');
    md5sum.update(str); // 确保使用UTF-8编码
    const md5Result = md5sum.digest();
    const sign = Buffer.from(md5Result).toString('base64');
    return sign;
}

function getZuiyouSignature2(params2, secret) {
    try {
        const keys = Object.keys(params2).sort();
        const kvPairs = keys.map(key => {
            const encodedKey = encodeURIComponent(key);
            const encodedValue = encodeURIComponent(params2[key]);
            return `${encodedKey}=${encodedValue}`;
        });
        const kvString = kvPairs.join('&');
        // logger.logMessage("urlParams>>>" + kvString);
        const hmac = crypto.createHmac('sha256', secret);
        hmac.update(kvString, 'utf8');
        const sign = hmac.digest('hex');
        // logger.logMessage("sign>>>" + sign);
        return sign;
    } catch (error) {
        logger.logMessage("HmacSHA256 签名生成失败: " + error.message);
        throw error;
    }
}

function formatTime(format = "yyyy-MM-dd HH:mm:ss") {
    const date = new Date();
    const year = date.getFullYear();
    const month = date.getMonth() + 1; // 月份是从 0 开始的，所以需要加 1
    const day = date.getDate();
    const hours = date.getHours();
    const minutes = date.getMinutes();
    const seconds = date.getSeconds();

    const formattedDate = format
        .replace("yyyy", `${year}`)
        .replace("MM", month < 10 ? `0${month}` : `${month}`)
        .replace("dd", day < 10 ? `0${day}` : `${day}`)
        .replace("HH", hours < 10 ? `0${hours}` : `${hours}`)
        .replace("mm", minutes < 10 ? `0${minutes}` : `${minutes}`)
        .replace("ss", seconds < 10 ? `0${seconds}` : `${seconds}`);

    return formattedDate;
}



module.exports = {
    requestAccessToken,
    onUpdateHoldRewardCoolingTime,
    onCheckHoldReward,
    getSignature,
    formatTime,
    getToken,
    getZuiyouSignature,
    getZuiyouSignature2
};